﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace IRUM.Utils
{
    public partial class IRUM_Chart : UserControl
    {
        string _date = string.Empty;
        List<ChartDataForDraw> _list = null;
        float _maxValue = 0f;
        float _minValue = 99999999f;
        float _maxIT_ABS = 0f;
        int _stickWidth = 0;
        int _stickGap = 1;
        int _widthYLabel = 50;

        public IRUM_Chart()
        {
            InitializeComponent();
        }

        public void SetData(string date, List<ChartDataForDraw> list)
        {
            _maxValue = 0f;
            _minValue = 99999999f;
            _maxIT_ABS = 0f;
            _stickWidth = 0;


            _date = date;
            _list = list;

            _stickWidth = (picChart.Width - _widthYLabel) / _list.Count - _stickGap;
            MakeMovingAverage();
        }

        private void MakeMovingAverage()
        {
            List<float> listMA05 = new List<float>();
            List<float> listMA20 = new List<float>();
            List<float> listMA60 = new List<float>();
            List<float> listMA120 = new List<float>();

            _list.Reverse();

            foreach (ChartDataForDraw data in _list)
            {
                //최대값 갱신
                _maxValue = Math.Max(_maxValue, data.high);

                //최소값 갱신
                _minValue = Math.Min(_minValue, data.low);

                //이평
                data.ma_05 = SetMovingAverage(listMA05, 5, data.close);
                data.ma_20 = SetMovingAverage(listMA20, 20, data.close);
                data.ma_60 = SetMovingAverage(listMA60, 60, data.close);
                data.ma_120 = SetMovingAverage(listMA120, 120, data.close);

                //수급최대절대값
                _maxIT_ABS = Math.Max(_maxIT_ABS, Math.Abs(data.it));
            }

            _maxValue = (Convert.ToInt32(_maxValue) / 5 + 1) * 5;
            _minValue = (Convert.ToInt32(_minValue) / 5 - 1) * 5;
        }

        private float SetMovingAverage(List<float> list, int length, float value)
        {
            float retVal = 0f;

            if (list.Count == length)
            {
                list.RemoveAt(0);
                list.Add(value);
            }
            else
            {
                list.Add(value);
            }

            if (list.Count == length)
            {
                retVal = list.Average();
            }

            return retVal;
        }

        private float GetYPosOfValue(float price)
        {
            float posMin = picChart.Height > 300 ? picChart.Height - 125 : picChart.Height - 25;
            float posValue = posMin - posMin * ((price - _minValue) / (_maxValue - _minValue));

            return posValue;
        }

        private float GetYPosOfIT(float it)
        {
            float posITBase = picChart.Height - 50;
            float posITMax = 45;
            float gapIT = posITMax * (Math.Abs(it)/_maxIT_ABS);
            float posIT = 0;

            if (it > 0)
            {
                posIT = posITBase - gapIT;
            }
            else
            {
                posIT = posITBase + gapIT;
            }

            return posIT;
        }

        public void DrawChart()
        {
#if true
            Bitmap bm = new Bitmap(picChart.Width, picChart.Height);
            Graphics g = Graphics.FromImage(bm);

            Brush brushWhite = new SolidBrush(Color.White);
            Brush brushGray = new SolidBrush(Color.Gray);
            Brush brushRed = new SolidBrush(Color.OrangeRed);
            Brush brushBlue = new SolidBrush(Color.RoyalBlue);
            Brush brushGold = new SolidBrush(Color.Gold);
            Brush brushBlack = new SolidBrush(Color.Black);
            Brush brushGreen = new SolidBrush(Color.YellowGreen);
            Brush brushYellow = new SolidBrush(Color.Goldenrod);
            Brush brushOrange = new SolidBrush(Color.Orange);
            Brush brushClose = new SolidBrush(Color.Yellow);
            Brush brushDDay = new SolidBrush(Color.LightPink);

            Pen penBorder = new Pen(brushBlack, 1.0f);
            Pen penAxis = new Pen(brushGray, 2.0f);
            Pen penGrid = new Pen(brushGray, 1.0f);
            Pen penMA05 = new Pen(brushGold, 1.0f);
            Pen penMA20 = new Pen(brushGreen, 1.0f);
            Pen penMA60 = new Pen(brushRed, 1.0f);
            Pen penMA120 = new Pen(brushBlue, 1.0f);
            Pen penPlus = new Pen(brushRed, 1.0f);
            Pen penMinus = new Pen(brushBlue, 1.0f);
            Pen penDogde = new Pen(brushBlack, 1.0f);

            //BG
            Rectangle rectBG = new Rectangle(0, 0, bm.Width, bm.Height);
            Rectangle rectBGBorder = new Rectangle(0, 0, bm.Width - 1, bm.Height - 1);
            g.FillRectangle(brushWhite, rectBG);
            g.DrawRectangle(penBorder, rectBGBorder);

            //Axis-X
            int posAxisX_Y = picChart.Height > 300 ? picChart.Height - 125 : picChart.Height - 25;  //충분한 높이가 되면 수급을 그려준다.
            g.DrawLine(penAxis, new Point(0, posAxisX_Y), new Point(picChart.Width - _widthYLabel, posAxisX_Y));

            //Axis-Y
            int posAxisY_X = picChart.Width - _widthYLabel;// (_stickWidth + _stickGap) * _list.Count;
            g.DrawLine(penAxis, new Point(posAxisY_X, 0), new Point(posAxisY_X, picChart.Height - 1));

            //만기일 표시, 기준일 표시
            int startPos = _stickGap;
            DateTime dday = new DateTime(Convert.ToInt32(_date.Substring(0, 4)), Convert.ToInt32(_date.Substring(4, 2)), Convert.ToInt32(_date.Substring(6, 2)));

            foreach (ChartDataForDraw data in _list)
            {
                DateTime thisDate = new DateTime(Convert.ToInt32(data.date.Substring(0, 4)), Convert.ToInt32(data.date.Substring(4, 2)), Convert.ToInt32(data.date.Substring(6, 2)));
                DateTime closeDate = IRUM_Utils.GetClosingDateOfOption(thisDate);
                
                if (thisDate == closeDate)
                {
                    g.FillRectangle(brushClose, new Rectangle(startPos, 1, _stickWidth + _stickGap, posAxisX_Y - 2));
                    g.FillRectangle(brushClose, new Rectangle(startPos, picChart.Height - 100, _stickWidth + _stickGap, 99));
                }

                if (thisDate == dday)
                {
                    g.FillRectangle(brushDDay, new Rectangle(startPos, 1, _stickWidth + _stickGap, posAxisX_Y - 2));
                    g.FillRectangle(brushDDay, new Rectangle(startPos, picChart.Height - 100, _stickWidth + _stickGap, 99));
                }

                startPos += _stickGap + _stickWidth;
            }

            //수급 0선
            if (picChart.Height > 300)
            {
                int posITLine_Y = picChart.Height - 50;  //충분한 높이가 되면 수급을 그려준다.
                g.DrawLine(penAxis, new Point(0, posITLine_Y), new Point(posAxisY_X, posITLine_Y));
            }

            //Grid
            float gridValue = _minValue;

            while (gridValue < _maxValue)
            {
                int posY = Convert.ToInt32(GetYPosOfValue(gridValue));
                g.DrawLine(penGrid, new Point(0, posY), new Point(posAxisY_X, posY));
                g.DrawString(gridValue.ToString("F02"), new Font("맑은 고딕", 10, FontStyle.Regular), brushBlack, new Point(posAxisY_X + 3, posY - 10));

                gridValue += 5;
            }



            //최대값, 최소값, 봉개수, 수급최대값, 최소값
            //1. Y축 - 가격/현재가
            //2. X축 - 날짜: 월 당일 만기일
            float prevMA05 = 0;
            float prevMA20 = 0;
            float prevMA60 = 0;
            float prevMA120 = 0;

            startPos = _stickGap;
            int prevMonth = 0;

            foreach (ChartDataForDraw data in _list)
            {
                //Guide Y
                DateTime thisDate = new DateTime(Convert.ToInt32(data.date.Substring(0, 4)), Convert.ToInt32(data.date.Substring(4, 2)), Convert.ToInt32(data.date.Substring(6, 2)));
                DateTime closeDate = IRUM_Utils.GetClosingDateOfOption(thisDate);
                int currMonth = thisDate.Month;

                if (prevMonth > 0 && prevMonth != currMonth)
                {
                    string displayDate = currMonth.ToString() + "/" + Convert.ToInt32(data.date.Substring(6, 2)).ToString();
                    g.DrawLine(penGrid, new Point(startPos, 2), new Point(startPos, posAxisX_Y));
                    g.DrawString(displayDate, new Font("맑은 고딕", 10, FontStyle.Regular), brushBlack, new Point(startPos-10, posAxisX_Y + 2));

                    g.DrawLine(penGrid, new Point(startPos, picChart.Height - 100), new Point(startPos, picChart.Height - 2));
                }

                prevMonth = currMonth;

                


                //이평선
                //5이평
                if (prevMA05 > 0)
                {
                    int pos_A = Convert.ToInt32(GetYPosOfValue(prevMA05));
                    int pos_B = Convert.ToInt32(GetYPosOfValue(data.ma_05));
                    g.DrawLine(penMA05, new Point(startPos, pos_A), new Point(startPos + _stickWidth, pos_B));
                }

                prevMA05 = data.ma_05;

                //20이평
                if (prevMA20 > 0)
                {
                    int pos_A = Convert.ToInt32(GetYPosOfValue(prevMA20));
                    int pos_B = Convert.ToInt32(GetYPosOfValue(data.ma_20));
                    g.DrawLine(penMA20, new Point(startPos, pos_A), new Point(startPos + _stickWidth, pos_B));
                }

                prevMA20 = data.ma_20;

                //60이평
                if (prevMA60 > 0)
                {
                    int pos_A = Convert.ToInt32(GetYPosOfValue(prevMA60));
                    int pos_B = Convert.ToInt32(GetYPosOfValue(data.ma_60));
                    g.DrawLine(penMA60, new Point(startPos, pos_A), new Point(startPos + _stickWidth, pos_B));
                }

                prevMA60 = data.ma_60;

                //120이평
                if (prevMA120 > 0)
                {
                    int pos_A = Convert.ToInt32(GetYPosOfValue(prevMA120));
                    int pos_B = Convert.ToInt32(GetYPosOfValue(data.ma_120));
                    g.DrawLine(penMA120, new Point(startPos, pos_A), new Point(startPos + _stickWidth, pos_B));
                }

                prevMA120 = data.ma_120;


                //캔들
                int pos_O = Convert.ToInt32(GetYPosOfValue(data.open));
                int pos_H = Convert.ToInt32(GetYPosOfValue(data.high));
                int pos_L = Convert.ToInt32(GetYPosOfValue(data.low));
                int pos_C = Convert.ToInt32(GetYPosOfValue(data.close));

                if (data.open > data.close)
                {
                    g.DrawLine(penMinus, new Point(startPos + _stickWidth / 2, pos_H), new Point(startPos + _stickWidth / 2, pos_L));
                    g.FillRectangle(brushBlue, new Rectangle(startPos, pos_O, _stickWidth, pos_C - pos_O + 1));
                }
                else if (data.open == data.close)
                {
                    g.DrawLine(penDogde, new Point(startPos + _stickWidth / 2, pos_H), new Point(startPos + _stickWidth / 2, pos_L));
                    g.FillRectangle(brushBlack, new Rectangle(startPos, pos_C, _stickWidth, 1));
                }
                else
                {
                    g.DrawLine(penPlus, new Point(startPos + _stickWidth / 2, pos_H), new Point(startPos + _stickWidth / 2, pos_L));
                    g.FillRectangle(brushRed, new Rectangle(startPos, pos_C, _stickWidth, pos_O - pos_C + 1));
                }



                //수급 - Height가 300 이하라면 수급은 그리지 않는다.
                int pos_it = Convert.ToInt32(GetYPosOfIT(data.it));

                if (picChart.Height > 300)
                {
                    int posITLine_Y = picChart.Height - 50;  //충분한 높이가 되면 수급을 그려준다.

                    if (data.it < 0)
                    {
                        g.FillRectangle(brushBlue, new Rectangle(startPos, posITLine_Y, _stickWidth, pos_it - posITLine_Y));
                    }
                    else if (data.it > 0)
                    {
                        g.FillRectangle(brushRed, new Rectangle(startPos, pos_it, _stickWidth, posITLine_Y - pos_it));
                    }
                }

                startPos += _stickGap + _stickWidth;
            }

            picChart.Image = bm;

#else

            chart1.Series["Candle"].Points.Clear();
            chart1.Series["IT"].Points.Clear();
            chart1.Series["MA05"].Points.Clear();
            chart1.Series["MA20"].Points.Clear();
            chart1.Series["MA60"].Points.Clear();
            chart1.Series["MA120"].Points.Clear();




            foreach (ChartDataForDraw d in _list)
            {
                DateTime dt = new DateTime(Convert.ToInt32(d.date.Substring(0, 4)), Convert.ToInt32(d.date.Substring(4, 2)), Convert.ToInt32(d.date.Substring(6, 2)));
                chart1.Series["Candle"].Points.AddXY(dt, d.open, d.high, d.low, d.close);
                chart1.Series["IT"].Points.AddXY(dt, d.it);

                if (d.ma_05 > 0)
                    chart1.Series["MA05"].Points.AddXY(dt, d.ma_05);

                if (d.ma_20 > 0)
                    chart1.Series["MA20"].Points.AddXY(dt, d.ma_20);

                if (d.ma_60 > 0)
                    chart1.Series["MA60"].Points.AddXY(dt, d.ma_60);

                if (d.ma_120 > 0)
                    chart1.Series["MA120"].Points.AddXY(dt, d.ma_120);
            }

            chart1.ChartAreas["지수"].RecalculateAxesScale();
#endif
        }
    }

    public class ChartDataForDraw
    {
        //날짜
        public string date = string.Empty;

        // 시가,고가,저가,종가
        public float open = 0f;
        public float high = 0f;
        public float low = 0f;
        public float close = 0f;

        //등락, 등락율
        public float change = 0f;
        public float rate = 0f;

        //이평
        public float ma_05 = 0f;
        public float ma_20 = 0f;
        public float ma_60 = 0f;
        public float ma_120 = 0f;

        //수급
        public int it = 0;
    }
}
